/**
 * 
 */
package org.stars.daostars.core;


import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;

import org.stars.daostars.conversion.TypeHandler;
import org.stars.daostars.core.runtime.columns.ArrayColumn;
import org.stars.daostars.core.runtime.columns.BooleanColumn;
import org.stars.daostars.core.runtime.columns.ByteColumn;
import org.stars.daostars.core.runtime.columns.ColumnProcessor;
import org.stars.daostars.core.runtime.columns.DoubleColumn;
import org.stars.daostars.core.runtime.columns.FloatColumn;
import org.stars.daostars.core.runtime.columns.IntegerColumn;
import org.stars.daostars.core.runtime.columns.LongColumn;
import org.stars.daostars.core.runtime.columns.ObjectColumn;
import org.stars.daostars.core.runtime.columns.ShortColumn;
import org.stars.daostars.core.runtime.columns.StringColumn;
import org.stars.daostars.core.runtime.columns.TimestampColumn;
import org.stars.daostars.core.runtime.columns.TypeHandlerColumn;
import org.stars.util.reflect.Getter;
import org.stars.util.reflect.Setter;

/**
 * @author Francesco Benincasa (908099)
 * 
 */
public class PropertyDescriptorEx {

	public PropertyDescriptorEx(Setter setterMethod, TypeHandler handler) {
		this.setter = setterMethod;
		this.name = setter.getPropertyName();
		this.typeHandler = handler;
		this.type = setter.getPropertyType();

		defineColumnProcessor();
	}
	
	public PropertyDescriptorEx(Getter setterMethod) {
		this.getter = setterMethod;
		this.name = getter.getPropertyName();
		this.type = getter.getPropertyType();
	}

	protected String	name;

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	protected TypeHandler	typeHandler;
	
	protected Class<?>		type;
	protected Setter		setter;
	protected Getter		getter;

	protected ColumnProcessor	columnProcessor;

	/**
	 * Questo metodo definisce il gestore della colonna in base all'handler (che
	 * pero' puo' essere anche null) ed in base al tipo di colonna da gestire.
	 */
	protected void defineColumnProcessor() {
		// nel caso di handler valido lo usiamo
		if (typeHandler != null) {
			columnProcessor = TypeHandlerColumn.instance;
		} else if (type.equals(String.class)) {
			columnProcessor = StringColumn.instance;

		} else if (type.equals(Integer.TYPE) || type.equals(Integer.class)) {
			columnProcessor = IntegerColumn.instance;

		} else if (type.equals(Boolean.TYPE) || type.equals(Boolean.class)) {
			columnProcessor = BooleanColumn.instance;

		} else if (type.equals(Long.TYPE) || type.equals(Long.class)) {
			columnProcessor = LongColumn.instance;

		} else if (type.equals(Double.TYPE) || type.equals(Double.class)) {
			columnProcessor = DoubleColumn.instance;

		} else if (type.equals(Float.TYPE) || type.equals(Float.class)) {
			columnProcessor = FloatColumn.instance;

		} else if (type.equals(Short.TYPE) || type.equals(Short.class)) {
			columnProcessor = ShortColumn.instance;

		} else if (type.equals(Byte.TYPE) || type.equals(Byte.class)) {
			columnProcessor = ByteColumn.instance;

		} else if (type.equals(Timestamp.class)) {
			columnProcessor = TimestampColumn.instance;

			// } else if (type.isArray() &&
			// type.getComponentType().equals(Byte.TYPE) &&
			// rs.getMetaData().getColumnType(index) == Types.BLOB) {
		} else if (type.isArray() && type.getComponentType().equals(Byte.TYPE)) {
			columnProcessor = ArrayColumn.instance;
		} else {
			columnProcessor = ObjectColumn.instance;
		}
	}

	/**
	 * @return the setterMethod
	 */
	public Setter getSetter() {
		return setter;
	}
	
	/**
	 * @return
	 */
	public Getter getGetter()
	{
		return getter;
	}
	
	public Object invokeGetter(Object obj) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
	{
		if (getter==null) return null;
		
		return getter.invoke(obj);
	}
	
	public void invokeSetter(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
	{
		if (setter==null) return;
		
		setter.invoke(obj, value);
	}
	
	/**
	 * @return the type
	 */
	public Class<?> getType() {
		return type;
	}

	/**
	 * @return the typeHandler
	 */
	public TypeHandler getTypeHandler() {
		return typeHandler;
	}

	public Object processColumn(ResultSet rs, int index) throws SQLException {
		return columnProcessor.execute(rs, index, type, typeHandler);
	}
}
